﻿
namespace N_dimenslArr
{
  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Linq;
  using System.Text;
  using Tao.FreeGlut;
  using Tao.OpenGl;
  using Tao.Platform;

  public class GeographyScene
  {
    public PeerScene peerScene = new PeerScene();
    private List<City> cities = new List<City>();
    public List<GeoLink> links = new List<GeoLink>();
    private Grid grid;
    private double sceneWidth;
    private double sceneHeight;
    private int viewportWidth;
    private int viewportHeight;
    private int squareSize;
    private double scaleRatio;
    private double aspectRatio;
    private double maxDimension;

    public GeographyScene()
    { }

    public GeographyScene(int viewportWidth, int viewportHeight, int squareSize)
    {
      Debug.Assert(squareSize != 0, "squareSize != 0");
      Debug.Assert(viewportHeight > 0, "viewportHeight > 0");
      Debug.Assert(viewportWidth > 0, "viewportWidth > 0");
      this.squareSize = squareSize;
      this.viewportWidth = viewportWidth;
      this.viewportHeight = viewportHeight;
      this.Zoom = 1;
      this.Shift = new double[2] { 0, 0 };
      this.sceneHeight = 1;
      this.sceneWidth = 1;
    }

    public GeographyScene(
           double sceneWidth,
           double sceneHeight,
           int viewportWidth,
           int viewportHeight,
           int squareSize)
    {
      this.Shift = new double[2] { 0, 0 };
      this.Zoom = 1;
      Debug.Assert(sceneHeight > 0, "sceneHeight > 0");
      Debug.Assert(sceneWidth > 0, "sceneWidth > 0");
      Debug.Assert(viewportHeight > 0, "viewportHeight > 0");
      Debug.Assert(viewportWidth > 0, "viewportWidth > 0");
      Debug.Assert(squareSize != 0, "squareSize != 0");
      this.sceneHeight = sceneHeight;
      this.sceneWidth = sceneWidth;
      this.viewportWidth = viewportWidth;
      this.viewportHeight = viewportHeight;
      this.squareSize = squareSize;
    }

    public bool isActiveScene { get; set; }

    public int MousePressX { get; set; }

    public int MousePressY { get; set; }

    public double[] Shift { get; set; }

    public double Zoom { get; set; }

    public bool Zooming { get; set; }

    public void InitGraphicsSystem()
    {
      this.maxDimension = Math.Max(this.sceneWidth, this.sceneHeight);
      this.aspectRatio = Convert.ToDouble(this.viewportHeight) / Convert.ToDouble(this.viewportWidth);
      this.scaleRatio = Convert.ToDouble(this.viewportWidth) / maxDimension;
      this.grid = new Grid(this.squareSize, this.viewportWidth, this.viewportHeight, this.scaleRatio);
      // инициализация Glut 
      if (Glut.glutGet(Glut.GLUT_ELAPSED_TIME) == 0)
      {
        Glut.glutInit();
        Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
      }
      // очитка окна 
      Gl.glClearColor(255, 255, 255, 1);

      // установка порта вывода в соотвествии с размерами элемента anT 
      Gl.glViewport(0, 0, this.viewportWidth, this.viewportHeight);

      // настройка проекции 
      Gl.glMatrixMode(Gl.GL_PROJECTION);
      Gl.glLoadIdentity();

      Gl.glOrtho(0, maxDimension, maxDimension, 0, -0.5, 0.5);

      Gl.glScaled(this.aspectRatio, 1, 1);

      Gl.glMatrixMode(Gl.GL_MODELVIEW);
      Gl.glLoadIdentity();

      // настройка параметров OpenGL для визуализации 
      Gl.glEnable(Gl.GL_DEPTH_TEST);
      Gl.glEnable(Gl.GL_COLOR_MATERIAL);
      Gl.glEnable(Gl.GL_BLEND);
      Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
      Gl.glEnable(Gl.GL_ALPHA_TEST);
      Gl.glEnable(Gl.GL_ALIASED_LINE_WIDTH_RANGE);
      Gl.glEnable(Gl.GL_ALIASED_POINT_SIZE_RANGE);
    }

    public void Move(int deltaX, int deltaY)
    {
      this.Shift[0] += Convert.ToDouble(deltaX) / (this.aspectRatio * this.scaleRatio);
      this.Shift[1] += Convert.ToDouble(deltaY) / (this.aspectRatio * this.scaleRatio);
      this.Render();
    }

    public void SetZoom(double delta)
    {
      this.Zoom += delta / (this.aspectRatio * this.scaleRatio);
      if (this.Zoom > 3)
      {
        this.Zoom = 3;
      }
      else if (this.Zoom < 1)
      {
        this.Zoom = 1;
      }
      this.Render();
    }

    public void AddCity(City city)
    {
      Debug.Assert(city != null, "city != null");
      this.cities.Add(city);
    }

    public void AddLink(GeoLink link)
    {
      Debug.Assert(link != null, "link != null");
      this.links.Add(link);
    }

    public void SetPeerScene(PeerScene scene)
    {
      Debug.Assert(scene != null, "scene != null");
      this.peerScene = scene;
    }

    public void ClrScr()
    {
      Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
    }

    private void SwapBuffers()
    {
      Gl.glFlush();
    }

    public void SetupCamera()
    {
    }

    public void Render()
    {
      this.ClrScr();
      this.SetupCamera();

      Gl.glLoadIdentity();
      Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
      Gl.glPushMatrix();

      this.grid.Render(this.Shift, this.Zoom);

      Gl.glPushAttrib(Gl.GL_ALL_ATTRIB_BITS);
      Gl.glColor3f(0, 0, 0);

      Gl.glLineWidth(1);
      Gl.glColor4f(0, 0, 0, 1);

      Gl.glLineWidth(5);
      Gl.glColor4f(0, 0, 1.0f, 0.4f);

      var corrX = (this.maxDimension / 2);
      var corrY = (this.maxDimension / 2);
      Gl.glTranslated(corrX, corrY, 0);

      Gl.glScaled(this.Zoom, this.Zoom, 1);

      //corrX /= -this.Zoom;
      //corrY /= -this.Zoom;
      Gl.glTranslated(-corrX , -corrY, 0);

      /* var mouseShiftX = 0.0;
       var mouseShiftY = 0.0;
       if (this.Zooming)
       {
         mouseShiftX = Convert.ToDouble(this.MousePressX) / (this.aspectRatio * this.scaleRatio);
         mouseShiftY = Convert.ToDouble(this.MousePressY) / (this.aspectRatio * this.scaleRatio);
       }

       corrX = (mouseShiftX / this.Zoom) - mouseShiftX;
       corrY = (mouseShiftY / this.Zoom) - mouseShiftY;
       Gl.glTranslated(corrX, corrY, 0);*/

      Gl.glTranslated(this.Shift[0] / this.Zoom, this.Shift[1] / this.Zoom, 0);
      
     /* Gl.glPushAttrib(Gl.GL_LINE_BIT);
      
      Gl.glLineWidth(5);
      Gl.glBegin(Gl.GL_LINE_LOOP);
      Gl.glVertex3d(0, 0, 0);
      Gl.glVertex3d(this.maxDimension, 0, 0);
      Gl.glVertex3d(this.maxDimension, this.maxDimension, 0);
      Gl.glVertex3d(0, this.maxDimension, 0);
      Gl.glEnd();

      Gl.glPopAttrib();*/

      foreach (City city in this.cities)
      {
        city.Render();
      }

      Gl.glColor3f(0, 0, 0);
      Gl.glPointSize(2.0f);
      this.peerScene.Zoom = this.Zoom;
      this.peerScene.Render();

      foreach (GeoLink link in this.links)
      {
        link.Render(this.Zoom);
      }

      Gl.glPopAttrib();
      Gl.glPopMatrix();

      this.SwapBuffers();
    }
  }
}
